package com.example.iso9797demo;

import org.junit.Test;
import static org.junit.Assert.*;

/**
 * ISO9797 MAC 计算测试类
 * 
 * 测试用例验证 ISO9797Alg3Mac 算法的正确性
 */
public class ISO9797MacTest {
    
    /**
     * 测试用例 1: 验证提供的测试向量
     * 
     * 输入数据: 84E400800F4F05474D504B49 (12字节)
     * 密钥:     319CD05D11BB06729BE23DA19B80E6A3 (16字节 双长度)
     * IV:       A097994108D06F1B (8字节)
     * 预期输出: F0E6EF6139D23733 (8字节)
     */
    @Test
    public void testProvidedTestVector() throws Exception {
        ISO9797MacHelper helper = new ISO9797MacHelper();
        
        // 测试数据（十六进制格式）
        String inputHex = "84E400800F4F05474D504B49";
        String keyHex = "319CD05D11BB06729BE23DA19B80E6A3";
        String ivHex = "A097994108D06F1B";
        String expectedOutput = "F0E6EF6139D23733";
        
        // 将输入数据转换为字节数组
        byte[] inputBytes = hexStringToBytes(inputHex);
        
        // 测试零填充 - 注意：这个测试数据实际使用 ISO7816-4 填充！
        String actualOutput = helper.calculateMACFromBytes(inputBytes, keyHex, ivHex, true);
        
        System.out.println("========== 测试用例 1: 提供的测试向量 ==========");
        System.out.println("输入数据 (Hex): " + inputHex);
        System.out.println("输入数据 (Bytes): " + bytesToString(inputBytes));
        System.out.println("密钥 (Hex): " + keyHex);
        System.out.println("密钥 (Bytes): " + bytesToString(hexStringToBytes(keyHex)));
        System.out.println("IV (Hex): " + ivHex);
        System.out.println("IV (Bytes): " + bytesToString(hexStringToBytes(ivHex)));
        System.out.println("预期输出 (Hex): " + expectedOutput);
        System.out.println("实际输出 (Hex): " + actualOutput);
        System.out.println("预期输出 (Bytes): " + bytesToString(hexStringToBytes(expectedOutput)));
        System.out.println("实际输出 (Bytes): " + bytesToString(hexStringToBytes(actualOutput)));
        System.out.println("测试结果: " + (expectedOutput.equalsIgnoreCase(actualOutput) ? "✓ 通过" : "✗ 失败"));
        System.out.println();
        
        assertEquals("MAC 输出不匹配", expectedOutput.toUpperCase(), actualOutput.toUpperCase());
    }
    
    /**
     * 测试用例 2: 使用 ISO7816-4 填充测试
     */
    @Test
    public void testWithISO7816Padding() throws Exception {
        ISO9797MacHelper helper = new ISO9797MacHelper();
        
        String inputHex = "84E400800F4F05474D504B49";
        String keyHex = "319CD05D11BB06729BE23DA19B80E6A3";
        String ivHex = "A097994108D06F1B";
        
        byte[] inputBytes = hexStringToBytes(inputHex);
        String output = helper.calculateMACFromBytes(inputBytes, keyHex, ivHex, true);
        
        System.out.println("========== 测试用例 2: ISO7816-4 填充 ==========");
        System.out.println("输入数据 (Hex): " + inputHex);
        System.out.println("密钥 (Hex): " + keyHex);
        System.out.println("IV (Hex): " + ivHex);
        System.out.println("填充模式: ISO7816-4");
        System.out.println("输出 (Hex): " + output);
        System.out.println("输出 (Bytes): " + bytesToString(hexStringToBytes(output)));
        System.out.println();
        
        assertNotNull("MAC 输出不应为空", output);
        assertEquals("MAC 长度应为 16 个十六进制字符（8 字节）", 16, output.length());
    }
    
    /**
     * 测试用例 3: 无 IV 的情况（对比）
     */
    @Test
    public void testWithoutIV() throws Exception {
        ISO9797MacHelper helper = new ISO9797MacHelper();
        
        String inputHex = "84E400800F4F05474D504B49";
        String keyHex = "319CD05D11BB06729BE23DA19B80E6A3";
        
        byte[] inputBytes = hexStringToBytes(inputHex);
        String outputWithoutIV = helper.calculateMACFromBytes(inputBytes, keyHex, null, false);
        String outputWithIV = helper.calculateMACFromBytes(inputBytes, keyHex, "A097994108D06F1B", false);
        
        System.out.println("========== 测试用例 3: IV 对比测试 ==========");
        System.out.println("输入数据 (Hex): " + inputHex);
        System.out.println("密钥 (Hex): " + keyHex);
        System.out.println("无 IV 输出: " + outputWithoutIV);
        System.out.println("有 IV 输出: " + outputWithIV);
        System.out.println("是否相同: " + (outputWithoutIV.equals(outputWithIV) ? "是" : "否"));
        System.out.println();
        
        assertNotEquals("使用 IV 和不使用 IV 的输出应该不同", outputWithoutIV, outputWithIV);
    }
    
    /**
     * 测试用例 4: 验证数据分析的准确性
     * 
     * 验证给定的两种格式（十六进制和字节数组）是否代表相同的数据
     */
    @Test
    public void testDataFormatConsistency() throws Exception {
        // 十六进制格式
        String inputHex = "84E400800F4F05474D504B49";
        String keyHex = "319CD05D11BB06729BE23DA19B80E6A3";
        String ivHex = "A097994108D06F1B";
        String expectedOutputHex = "F0E6EF6139D23733";
        
        // 字节数组格式（从用户提供的数据）
        byte[] inputBytes = new byte[] {
            (byte)0x84, (byte)0xE4, 0x00, (byte)0x80, 0x0F, 0x4F, 0x05, 0x47, 
            0x4D, 0x50, 0x4B, 0x49
        };
        byte[] keyBytes = new byte[] {
            0x31, (byte)0x9C, (byte)0xD0, 0x5D, 0x11, (byte)0xBB, 0x06, 0x72, 
            (byte)0x9B, (byte)0xE2, 0x3D, (byte)0xA1, (byte)0x9B, (byte)0x80, (byte)0xE6, (byte)0xA3
        };
        byte[] ivBytes = new byte[] {
            (byte)0xA0, (byte)0x97, (byte)0x99, 0x41, 0x08, (byte)0xD0, 0x6F, 0x1B
        };
        byte[] expectedOutputBytes = new byte[] {
            (byte)0xF0, (byte)0xE6, (byte)0xEF, 0x61, 0x39, (byte)0xD2, 0x37, 0x33
        };
        
        System.out.println("========== 测试用例 4: 数据格式一致性验证 ==========");
        
        // 验证输入数据
        String convertedInputHex = bytesToHexString(inputBytes);
        System.out.println("原始输入 (Hex):    " + inputHex);
        System.out.println("字节转换 (Hex):    " + convertedInputHex);
        assertEquals("输入数据格式转换不一致", inputHex.toUpperCase(), convertedInputHex.toUpperCase());
        
        // 验证密钥
        String convertedKeyHex = bytesToHexString(keyBytes);
        System.out.println("原始密钥 (Hex):    " + keyHex);
        System.out.println("字节转换 (Hex):    " + convertedKeyHex);
        assertEquals("密钥格式转换不一致", keyHex.toUpperCase(), convertedKeyHex.toUpperCase());
        
        // 验证 IV
        String convertedIvHex = bytesToHexString(ivBytes);
        System.out.println("原始 IV (Hex):     " + ivHex);
        System.out.println("字节转换 (Hex):    " + convertedIvHex);
        assertEquals("IV 格式转换不一致", ivHex.toUpperCase(), convertedIvHex.toUpperCase());
        
        // 验证预期输出
        String convertedOutputHex = bytesToHexString(expectedOutputBytes);
        System.out.println("原始预期输出 (Hex): " + expectedOutputHex);
        System.out.println("字节转换 (Hex):    " + convertedOutputHex);
        assertEquals("预期输出格式转换不一致", expectedOutputHex.toUpperCase(), convertedOutputHex.toUpperCase());
        
        System.out.println("✓ 所有数据格式转换一致");
        System.out.println();
    }
    
    /**
     * 测试用例 5: 完整的测试向量验证（字节数组输入）
     */
    @Test
    public void testWithByteArrayInput() throws Exception {
        ISO9797MacHelper helper = new ISO9797MacHelper();
        
        // 使用字节数组格式的数据
        byte[] inputBytes = new byte[] {
            (byte)0x84, (byte)0xE4, 0x00, (byte)0x80, 0x0F, 0x4F, 0x05, 0x47, 
            0x4D, 0x50, 0x4B, 0x49
        };
        String keyHex = "319CD05D11BB06729BE23DA19B80E6A3";
        String ivHex = "A097994108D06F1B";
        String expectedOutput = "F0E6EF6139D23733";
        
        String actualOutput = helper.calculateMACFromBytes(inputBytes, keyHex, ivHex, true);
        
        System.out.println("========== 测试用例 5: 字节数组输入测试 ==========");
        System.out.println("输入数据: " + bytesToString(inputBytes));
        System.out.println("输入数据 (Hex): " + bytesToHexString(inputBytes));
        System.out.println("预期输出: " + expectedOutput);
        System.out.println("实际输出: " + actualOutput);
        System.out.println("测试结果: " + (expectedOutput.equalsIgnoreCase(actualOutput) ? "✓ 通过" : "✗ 失败"));
        System.out.println();
        
        assertEquals("MAC 输出不匹配", expectedOutput.toUpperCase(), actualOutput.toUpperCase());
    }
    
    // ========== 辅助方法 ==========
    
    /**
     * 十六进制字符串转字节数组
     */
    private byte[] hexStringToBytes(String hex) {
        hex = hex.replaceAll("\\s+", "");
        int len = hex.length();
        byte[] data = new byte[len / 2];
        
        for (int i = 0; i < len; i += 2) {
            int high = Character.digit(hex.charAt(i), 16);
            int low = Character.digit(hex.charAt(i + 1), 16);
            data[i / 2] = (byte) ((high << 4) | low);
        }
        
        return data;
    }
    
    /**
     * 字节数组转十六进制字符串
     */
    private String bytesToHexString(byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        for (byte b : bytes) {
            sb.append(String.format("%02X", b & 0xFF));
        }
        return sb.toString();
    }
    
    /**
     * 字节数组转字符串表示（用于调试输出）
     */
    private String bytesToString(byte[] bytes) {
        StringBuilder sb = new StringBuilder("[");
        for (int i = 0; i < bytes.length; i++) {
            if (i > 0) sb.append(", ");
            sb.append(bytes[i]);
        }
        sb.append("]");
        return sb.toString();
    }
}
